const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const path = require("path");
const crypto = require("crypto");
const fs = require("fs");
const log = require("./utils/log.js");

// Server Settings
const port = 3210;
const TAG = "Server";

// ErrorCode Define
const EC_SUCCESS = 0;
const EC_UNKNOWN = 1;

const responseJsonVO = {
  code: EC_SUCCESS,
  msg: null,
  data: null
};

app.use(
  bodyParser.json({
    limit: "1mb"
  })
);
app.use(
  bodyParser.urlencoded({
    extended: true
  })
);

app.get("/", (req, res) => res.send("Hello World!"));

// Get all Module ID
let localRepoVO = {};
let localCurrentId = 0;
let localIdMaps = new Map();
const localRepoFilePath = "./repo_for_ids.json";
app.get("/module/ids", (req, res) => {
  log.i("All_Id", `Get All Ids with length = ${localRepoVO.data.length}`);
  res.send(localRepoVO);
});

// Create A Module ID
/*
 {
	"relativePath":"fileRelativePath",
	"hashInHex":"asdfasdfasdf",
	"hashType":"sha256",
    "size":234,
    "code":"....."
    "type":"common"
}
 */
app.post("/module/id/create", (req, res) => {
  // log.i(TAG, JSON.stringify(req.body));
  let reqData = req.body;
  let element = getOrCreateModuleId(
    reqData.findKey,
    reqData.relativePath,
    reqData.hashInHex,
    reqData.hashType,
    reqData.size,
    reqData.type
  );
  let jsonResponse = responseJsonVO;
  jsonResponse.msg = "成功";
  jsonResponse.data = element;
  res.send(jsonResponse);
});

function buildFindKey(relativePath, hashInHex) {
  let sha256 = crypto.createHash("sha256");
  sha256.update(`${hashInHex}${relativePath}`);
  let findKey = sha256.digest("hex");
  return findKey;
}

function getOrCreateModuleId(
  findKey,
  relativePath,
  hashInHex,
  hashType,
  size,
  type
) {
  if (null == findKey) {
    findKey = buildFindKey(relativePath, hashInHex);
  }
  let startTime = new Date().getTime();
  let tag = "Find_Id";
  if (!localIdMaps.has(findKey)) {
    tag = "Create_Id";
    let element = {};
    element.relativePath = relativePath;
    element.hashInHex = hashInHex;
    element.hashType = hashType;
    element.code = "";
    element.size = size;
    element.type = type;
    element.findKey = findKey;
    element.id = ++localCurrentId;
    // add to local data
    localRepoVO.data.push(element);
    localIdMaps.set(findKey, element);
    saveRepoToFile();
  }
  let ret = localIdMaps.get(findKey);
  log.i(
    tag,
    `Handle id= ${ret.id}, Time Cost: ${new Date().getTime() - startTime} ms`
  );
  return ret;
}

app.listen(port, () => {
  log.i(TAG, "##############################################");
  log.i(TAG, "# Global Module ID Service For React Native");
  log.i(TAG, `# Listening at port : ${port}`);
  log.i(TAG, "##############################################");
  log.i(TAG, ".... Data Initilization Start ....");
  init();
  log.i(TAG, ".... Data Initilization End ....");
});

function init() {
  if (fs.existsSync(localRepoFilePath)) {
    log.i(TAG, `File ${localRepoFilePath} exist and update local Repo.`);
    updateRepoFromFile();
    updateCurrentId();
  } else {
    log.i(TAG, `Create File ${localRepoFilePath}.`);
    createRepo();
    updateRepoFromFile();
    updateCurrentId();
  }
}

function updateRepoFromFile() {
  var data = fs.readFileSync(localRepoFilePath);
  localRepoVO = JSON.parse(data);
}

function updateCurrentId() {
  if (localRepoVO.data instanceof Array) {
    localIdMaps = new Map();
    localRepoVO.data.forEach(element => {
      localCurrentId =
        localCurrentId >= element.id ? localCurrentId : element.id;
      // init local map for find the quick;
      localIdMaps.set(element.findKey, element);
    });
    log.i(TAG, `localCurrentId = ${localCurrentId}`);
  }
}

function createRepo() {
  localRepoVO = responseJsonVO;
  localRepoVO.code = EC_SUCCESS;
  localRepoVO.data = [];
  localRepoVO.msg = "";
  saveRepoToFile();
}

function saveRepoToFile() {
  var data = JSON.stringify(localRepoVO);
  fs.writeFileSync(localRepoFilePath, data);
}
